import 'package:flutter/widgets.dart';
import 'package:flutter_dva/flutter_dva.dart';
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;

class DvaConnect {
  Props? props;
  Map<String, StoreOfState>? state;
  Store? store;
}

typedef MapState = Map<String, StoreOfState> Function(Map<String, StoreOfState> rootState);
typedef ShouldUpdate = bool Function(StoreOfState lState, StoreOfState nState);

DvaConnect useDvaConnect({
  String? namespace,
  List<String>? listenKeys,
  MapState? mapState,
  ShouldUpdate? shouldUpdate,
  VoidCallback? didMounted
}) {
  return use(
    _DvaConnectHook(
      namespace: namespace,
      listenKeys: listenKeys,
      mapState: mapState,
      shouldUpdate: shouldUpdate,
      didMounted: didMounted
    ),
  );
}

class _DvaConnectHook extends Hook<DvaConnect> {
  final String? namespace;
  final List<String>? listenKeys;
  final MapState? mapState;
  final ShouldUpdate? shouldUpdate;
  final VoidCallback? didMounted;

  const _DvaConnectHook({ this.shouldUpdate, this.didMounted, this.listenKeys, this.mapState, this.namespace });

  @override
  _DvaConnectHookState createState() =>_DvaConnectHookState();
}

class _DvaConnectHookState extends HookState<DvaConnect, _DvaConnectHook> {
  late DvaConnect connect;
  bool _mounted = false;
  StateChangeFunction? storeSubCallback;

  bool shouldUpdate(StoreOfState lState, StoreOfState nState) => lState.updateAt?.millisecondsSinceEpoch != nState.updateAt?.millisecondsSinceEpoch;

  /// 建议加载数据
  @mustCallSuper
  void didMounted() {
    _mounted = true;
    if(hook.didMounted != null) hook.didMounted!();
  }

  initConnect() {
    connect = DvaConnect();
    connect.store = Provider().store;
    connect.state = hook.mapState == null ? connect.store!.rootState : hook.mapState!(connect.store!.rootState);
    connect.props = Props(namespace: hook.namespace);
  }

  initStoreCallback() {
    storeSubCallback = (StoreOfState lState, StoreOfState nState) {
      if(hook.listenKeys != null && hook.listenKeys?.contains(nState.namespace) != true) return;
      if(connect.state?.containsKey(nState.namespace) != true) return;
      if(!shouldUpdate(lState, nState)) return;
      if(hook.shouldUpdate != null && !shouldUpdate(lState, nState)) return;
      setState(()=><String, Function>{});
    };
    connect.store!.subscribe(storeSubCallback!);
    if(_mounted == false) {
      Future<dynamic>.delayed(const Duration(milliseconds: 10)).whenComplete((){
        didMounted();
      });
    }
  }

  @override
  void initHook() {
    initConnect();
    initStoreCallback();
    super.initHook();
  }

  @override
  void dispose() {
    connect.store!.remove(storeSubCallback!);
    _mounted = false;
    super.dispose();
  }

  @override
  DvaConnect build(BuildContext context) {
    return connect;
  }
}


